﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;
using ESRI.ArcGIS.Carto;
using ESRI.ArcGIS.Geodatabase;
using ESRI.ArcGIS.Geometry;

namespace PlanningGIS.ArcGIS
{
    /// <summary>
    /// 地图操作类
    /// </summary>
    public class MapHelper
    {
        /// <summary>
        /// 通过IFeatureClass获得一个Map中所有与该FeatureClass相同Dataset的Featurelayer。
        /// 注意不能用IFeatureClass.aliasname
        /// </summary>
        /// <param name="map">地图</param>
        /// <param name="featCls">要素类</param>
        /// <returns></returns>
        public static List<IFeatureLayer> FindFeatureLayer(IMap map, IFeatureClass featCls)
        {
            List<IFeatureLayer> listFeatLyr = new List<IFeatureLayer>();
            List<IFeatureLayer> lyrCol = GetAllLayer<IFeatureLayer>(map);
            IDataset ds = featCls as IDataset;
            foreach (IFeatureLayer lyr in lyrCol)
            {
                IFeatureClass tempFeatCls = lyr.FeatureClass;
                IDataset tempDs = tempFeatCls as IDataset;
                if (ds.Workspace.Equals(tempDs.Workspace))
                {
                    //sdc后缀的要素类文件objectclassid总为-1
                    if (tempFeatCls.ObjectClassID == -1 || featCls.ObjectClassID == -1)
                    {
                        if (ds.Name.Equals(tempDs.Name,StringComparison.CurrentCultureIgnoreCase))
                            listFeatLyr.Add(lyr);
                    }
                    else
                    {
                        if (tempFeatCls.ObjectClassID == featCls.ObjectClassID)
                            listFeatLyr.Add(lyr);
                    }
                }
            }
            return listFeatLyr;
        }

        /// <summary>
        /// 返回图层包含指定字符串的图层，如果有多个图层同名，只返回第一图层，不考虑同名现象
        /// </summary>
        /// <param name="map">地图</param>
        /// <param name="containString">名称包含的字符串</param>
        /// <returns></returns>
        public static IFeatureLayer FindFeatureLayerByPartialName(IMap map, string containString)
        {
            Dictionary<string, IFeatureLayer> featLyrs = GetAllFeatureLayer(map);
            KeyValuePair<string, IFeatureLayer> kvp = featLyrs.FirstOrDefault(t => t.Key.ToUpper().Contains(containString.ToUpper()));
            if (string.IsNullOrEmpty(kvp.Key)) return null;
            return kvp.Value;
        }

        /// <summary>
        /// 根据IDataset获取一个Map中所有与该IDataset相同的图层
        /// </summary>
        /// <param name="map">地图</param>
        /// <param name="ds"></param>
        /// <returns></returns>
        public static List<ILayer> FindLayers(IMap map, IDataset ds)
        {
            List<ILayer> layers = new List<ILayer>();
            List<ILayer> arrayList = GetAllLayer(map);
            foreach (ILayer lyr in arrayList)
            {
                if (lyr is IFeatureLayer)
                {
                    IDataset tempDs = ((IFeatureLayer)lyr).FeatureClass as IDataset;
                    if (ds.Workspace.Equals(tempDs.Workspace))
                    {
                        //sdc后缀的要素类文件objectclassid总为-1
                        if (((IFeatureClass)tempDs).ObjectClassID == -1 || ((IFeatureClass)ds).ObjectClassID == -1)
                        {
                            if (ds.Name.Equals(tempDs.Name, StringComparison.CurrentCultureIgnoreCase))
                                layers.Add(lyr);
                        }
                        else
                        {
                            if (((IFeatureClass)tempDs).ObjectClassID == ((IFeatureClass)ds).ObjectClassID)
                                layers.Add(lyr);
                        }
                    }
                }
                else if (lyr is IRasterLayer)
                {
                    if (lyr.Name.Equals(ds.Name, StringComparison.CurrentCultureIgnoreCase))
                        layers.Add(lyr);
                }
                else if (lyr is IGdbRasterCatalogLayer)
                {
                    if (lyr.Name.Equals(ds.Name, StringComparison.CurrentCultureIgnoreCase))
                        layers.Add(lyr);
                }
            }
            return layers;
        }

        /// <summary>
        /// 获取当前所有可见，可选择，非注记的FeatureLayer
        /// </summary>
        /// <param name="map"></param>
        /// <returns></returns>
        public static IList<IFeatureLayer> GetFeatureLayer(IMap map)
        {
            List<IFeatureLayer> Layers = GetAllLayer<IFeatureLayer>(map);
            //去除不可见图层，注记层，无效层，不可选择层，栅格层等
            IList<IFeatureLayer> featLyr = new List<IFeatureLayer>();
            foreach (IFeatureLayer lyr in Layers)
            {
                if (lyr.Visible && lyr.Selectable && lyr.FeatureClass != null
                    && lyr.FeatureClass.FeatureType != esriFeatureType.esriFTAnnotation)
                {
                    featLyr.Add(lyr);
                }
            }
            if (featLyr.Count < 1) return null;
            else return featLyr;
        }

        /// <summary>
        /// 获取地图中的所有图层
        /// </summary>
        /// <param name="map">地图</param>
        /// <returns></returns>
        public static List<ILayer> GetAllLayer(IMap map)
        {
            List<ILayer> layers = new List<ILayer>();
            int count = map.LayerCount;
            for (int i = 0; i < count; i++)
            {
                ILayer lyr = map.get_Layer(i);
                GetAllLayer(lyr, layers);
            }
            return layers;
        }

        /// <summary>
        /// 获取图层或图层组中的所有图层
        /// </summary>
        /// <param name="layer">图层或图层组</param>
        /// <param name="layers">图层集合</param>
        public static void GetAllLayer(ILayer layer, List<ILayer> layers)
        {
            if (layer is IAnnotationLayer || layer is ICadLayer)
            {
                layers.Add(layer);
            }
            else if (layer is ICompositeLayer)
            {
                int count = (layer as ICompositeLayer).Count;
                for (int i = 0; i < count; i++)
                {
                    ILayer lyr = (layer as ICompositeLayer).get_Layer(i);
                    GetAllLayer(lyr, layers);
                }
            }
            else
            {
                layers.Add(layer);
            }
        }

        /// <summary>
        /// 获取地图中指定类型的所有图层
        /// </summary>
        /// <typeparam name="T">图层类型</typeparam>
        /// <param name="map">地图</param>
        /// <returns></returns>
        public static List<T> GetAllLayer<T>(IMap map)
        {
            List<ILayer> layers = GetAllLayer(map);
            if (layers == null || layers.Count == 0) return null;
            List<T> newLayers = new List<T>();
            foreach (ILayer lyr in layers)
            {
                if (lyr is T)
                {
                    newLayers.Add((T)lyr);
                }
            }
            return newLayers;
        }

        /// <summary>
        /// 获取图层组中指定类型的图层集合
        /// </summary>
        /// <typeparam name="T">图层类型，如ILayer、IFeatureLayer、IRasterLayer等</typeparam>
        /// <param name="lyr">图层组</param>
        /// <param name="layers">引用的图层集合对象</param>
        /// <returns></returns>
        public static void GetAllLayer<T>(ILayer lyr, List<T> layers)
        {
            List<ILayer> tmplyrs = new List<ILayer>();
            GetAllLayer(lyr, tmplyrs);
            if (tmplyrs == null || tmplyrs.Count == 0) return;
            if (layers == null) layers = new List<T>();
            foreach (ILayer l in tmplyrs)
            {
                if (l is T)
                {
                    layers.Add((T)l);
                }
            }
        }

        /// <summary>
        /// 获取地图中所有FeatureLayer的名称
        /// </summary>
        /// <param name="map">地图</param>
        /// <returns>名称列表</returns>
        public static List<string> GetFeaturelayerNames(IMap map)
        {
            List<string> lyrnameArray = new List<string>();
            Dictionary<string, IFeatureLayer> featLyrs = GetAllFeatureLayer(map);
            var v = from k in featLyrs
                    select k.Key;
            return v.ToList();
        }

        /// <summary>
        /// 获取地图中的所有IFeatureLayer图层，返回结果以FeatureClass的名称作为键值
        /// </summary>
        /// <param name="map">所在的地图</param>
        /// <returns></returns>
        public static Dictionary<string, IFeatureLayer> GetAllFeatureLayer(IMap map)
        {
            Dictionary<string, IFeatureLayer> layers = new Dictionary<string, IFeatureLayer>();
            int count = map.LayerCount;
            for (int i = 0; i < count; i++)
            {
                ILayer lyr = map.get_Layer(i);
                GetAllFeatureLayer(lyr, layers);
            }
            return layers;
        }

        /// <summary>
        /// 获取图层组中的所有IFeatureLayer图层，返回结果以FeatureClass的名称作为键值
        /// </summary>
        /// <param name="layer">图层或图层组</param>
        /// <param name="layers">IFeatureLayer图层集合</param>
        public static void GetAllFeatureLayer(ILayer layer, Dictionary<string, IFeatureLayer> layers)
        {
            if (layer is IAnnotationLayer || layer is IFeatureLayer)
            {
                if ((layer as IFeatureLayer) == null) return;
                IFeatureClass fcl = (layer as IFeatureLayer).FeatureClass;
                if (fcl == null) return;
                IDataset dataSet = fcl as IDataset;
                if (dataSet == null) return;
                string name = ((layer as IFeatureLayer).FeatureClass as IDataset).Name.ToUpper();
                int index = name.LastIndexOf(".");
                if (index >= 0) name = name.Substring(index + 1, name.Length - index - 1);
                if (layers.ContainsKey(name)) return;
                layers.Add(name, layer as IFeatureLayer);
            }
            else if (layer is ICompositeLayer)
            {
                int count = (layer as ICompositeLayer).Count;
                for (int i = 0; i < count; i++)
                {
                    ILayer lyr = (layer as ICompositeLayer).get_Layer(i);
                    GetAllFeatureLayer(lyr, layers);
                }
            }
        }

        /// <summary>
        /// 获取地图中第一个指定的图层名称的图层，不区分图层类型
        /// </summary>
        /// <param name="map">地图</param>
        /// <param name="layername">图层名称</param>
        /// <param name="isFeatureClassName">图层名称是否为对应的数据表的名称</param>
        /// <returns></returns>
        public static ILayer GetFirstLayer(IMap map, string layername, bool isFeatureClassName = false)
        {
            int count = map.LayerCount;
            for (int i = 0; i < count; i++)
            {
                ILayer lyr = map.get_Layer(i);
                ILayer l = GetFirstLayer(lyr, layername, isFeatureClassName);
                if (l != null)
                    return l;
            }
            return null;
        }

        /// <summary>
        /// 获取图层组中第一个指定的图层名称的图层，不区分图层类型
        /// </summary>
        /// <param name="layer">图层或图层组</param>
        /// <param name="layername">图层名称</param>
        /// <param name="isFeatureClassName">图层名称是否为对应的数据表的名称</param>
        /// <returns></returns>
        public static ILayer GetFirstLayer(ILayer layer, string layername, bool isFeatureClassName = false)
        {
            if (layer is IFeatureLayer)
            {
                string name = layer.Name.ToUpper();
                if (isFeatureClassName)  
                {
                    IFeatureClass cls = (layer as IFeatureLayer).FeatureClass;
                    if (cls != null) name = (cls as IDataset).Name.ToUpper();
                }
                int index = name.LastIndexOf(".");
                int index2 = layername.LastIndexOf(".");
                if (index > 0 && index2 > 0)
                {
                    if (name.Equals(layername, StringComparison.CurrentCultureIgnoreCase))
                        return layer;
                }
                else
                {
                    if (index >= 0) name = name.Substring(index + 1, name.Length - index - 1);
                    if (index2 >= 0) layername = layername.Substring(index + 1, layername.Length - index - 1);
                    if (name.Equals(layername, StringComparison.CurrentCultureIgnoreCase))
                        return layer;
                }
                
            }
            else
            {
                if (layer.Name.Equals(layername, StringComparison.CurrentCultureIgnoreCase))
                    return layer;
                if (layer is ICompositeLayer)
                {
                    int count = (layer as ICompositeLayer).Count;
                    for (int i = 0; i < count; i++)
                    {
                        ILayer lyr = (layer as ICompositeLayer).get_Layer(i);
                        ILayer l = GetFirstLayer(lyr, layername);
                        if (l != null)
                            return l;
                    }
                }
            }
            return null;
        }

        /// <summary>
        /// 获取地图中第一个指定的图层名称的图层，不区分图层类型
        /// </summary>
        /// <param name="map">地图</param>
        /// <param name="layername">图层名称，若去IFeatureLayer，则名称为数据集实际的表名称</param>
        /// <param name="isFeatureClassName">图层名称是否为对应的数据表的名称</param>
        /// <returns></returns>
        public static T GetFirstLayer<T>(IMap map, string layername, bool isFeatureClassName = false)
        {
            int count = map.LayerCount;
            for (int i = 0; i < count; i++)
            {
                ILayer lyr = map.get_Layer(i);
                T l = GetFirstLayer<T>(lyr, layername, isFeatureClassName);
                if (l != null && !l.Equals(default(T)))
                    return l;
            }
            return default(T);
        }

        /// <summary>
        /// 获取图层组中第一个指定的图层名称的图层，不区分图层类型
        /// </summary>
        /// <param name="layer">图层或图层组</param>
        /// <param name="layername">图层显示的名称，而不是图层数据集实际的数据表名称</param>
        /// <param name="isFeatureClassName">图层名称是否为对应的数据表的名称</param>
        /// <returns></returns>
        public static T GetFirstLayer<T>(ILayer layer, string layername, bool isFeatureClassName = false)
        {
            if (layer is IFeatureLayer)
            {
                if (!(layer is T)) return default(T);
                string name = layer.Name;
                if(isFeatureClassName)
                    name = ((layer as IFeatureLayer).FeatureClass as IDataset).Name.ToUpper();
                int index = name.LastIndexOf(".");
                if (index >= 0)
                    name = name.Substring(index + 1, name.Length - index - 1);
                if (name.Equals(layername, StringComparison.CurrentCultureIgnoreCase))
                    return (T)layer;
            }
            else
            {
                if (layer.Name.Equals(layername, StringComparison.CurrentCultureIgnoreCase))
                {
                    if (layer is T) return (T)layer;
                }
                if (layer is ICompositeLayer)
                {
                    int count = (layer as ICompositeLayer).Count;
                    for (int i = 0; i < count; i++)
                    {
                        ILayer lyr = (layer as ICompositeLayer).get_Layer(i);
                        ILayer l = GetFirstLayer(lyr, layername);
                        if (l != null)
                            return (T)l;
                    }
                }
            }
            return default(T);
        }
        
        /// <summary>
        /// 获取地图中所有可选的图层
        /// </summary>
        /// <param name="map"></param>
        /// <returns></returns>
        public static List<IFeatureLayer> GetSelectableLayers(IMap map)
        {
            List<IFeatureLayer> layers = GetAllLayer<IFeatureLayer>(map);
            return layers.FindAll(t => t.Selectable);
        }

        /// <summary>
        /// 获得map中所有可见IFeatureLayer的集合，
        /// 在使用过程中最好先用IFeatureLayer.Valid进行判断
        /// IFeatureLayer.Visible和比例尺显示范围的判断
        /// </summary>
        /// <param name="map"></param>
        /// <returns></returns>
        public static List<T> GetVisibleLayers<T>(IMap map)
        {
            List<T> layers = new List<T>();
            if (map == null || map.LayerCount == 0) return layers;
            int count = map.LayerCount;
            for (int i = 0; i < count; i++)
            {
                ILayer lyr = map.get_Layer(i);
                if (!lyr.Valid) continue;
                GetVisibleLayers<T>(lyr, layers, map);
            }
            return layers;
        }

        /// <summary>
        /// 获取图层组中可见的图层
        /// </summary>
        /// <param name="layer"></param>
        /// <param name="layers"></param>
        /// <param name="map"></param>
        public static void GetVisibleLayers<T>(ILayer layer, List<T> layers, IMap map)
        {
            if (IsVisibleLayer(layer, map) == true)
            {
                if (layer is ICompositeLayer)
                {
                    ICompositeLayer pCompositeLyr = layer as ICompositeLayer;
                    for (int i = 0; i < pCompositeLyr.Count; i++)
                    {
                        ILayer pLyr2 = pCompositeLyr.get_Layer(i);
                        GetVisibleLayers<T>(pLyr2, layers, map);
                    }
                }
                else if (layer is T)
                {
                    layers.Add((T)layer);
                }
            }
        }

        /// <summary>
        /// 判断图层是否可见
        /// </summary>
        /// <param name="layer"></param>
        /// <param name="map"></param>
        /// <returns></returns>
        public static bool IsVisibleLayer(ILayer layer, IMap map)
        {
            if (layer.Visible == true)
            {
                if ((layer.MaximumScale < map.MapScale && layer.MinimumScale > map.MapScale) ||
                    (layer.MaximumScale < map.MapScale && layer.MinimumScale == 0) ||
                    (layer.MaximumScale == 0 && layer.MinimumScale > map.MapScale) ||
                    (layer.MaximumScale == 0 && layer.MinimumScale == 0))
                {
                    return true;
                }
                else
                {
                    return false;
                }
            }
            return false;
        }

        /// <summary>
        /// 设置图层组下子图层的可见性，若可见时同时设置该图层组下的所有图层
        /// </summary>
        /// <param name="compositeLayer">图层组</param>
        /// <param name="visible">显示状态</param>
        public static void SetCompositeLayerVisiable(ICompositeLayer compositeLayer, bool visible)
        {
            for (int i = 0; i < compositeLayer.Count; i++)
            {
                ILayer lyr = compositeLayer.get_Layer(i);
                lyr.Visible = visible;
                if (visible && lyr is ICompositeLayer)
                    SetCompositeLayerVisiable((ICompositeLayer)lyr, visible);
            }
        }

        /// <summary>
        /// 得到map上有效的feature layer 的数目
        /// </summary>
        /// <param name="map">所在的地图</param>
        /// <returns></returns>
        public static int GetFeatureLayerCount(IMap map)
        {
            int count = 0;
            if (map == null || map.LayerCount == 0) return 0;
            IEnumLayer layers = map.get_Layers(null, true);
            ILayer layer = layers.Next();
            while (layer != null)
            {
                if ((layer.Valid == true) && (layer is IFeatureLayer))
                {
                    count++;
                }
                layer = layers.Next();
            }
            Marshal.ReleaseComObject(layers);
            return count;
        }

        /// <summary>
        /// 从地图中获取所有图层
        /// </summary>
        /// <param name="map"></param>
        /// <param name="geometryType">指定何种几何类型的数据需要获取</param>
        /// <param name="featureType">指定何种数据类型的数据需要获取</param>
        /// <param name="needVisable">指定是否图层可见才获取</param>
        /// <returns></returns>
        public static List<IFeatureLayer> GetFeaturelayers(IMap map, esriGeometryType geometryType, esriFeatureType featureType, bool needVisable)
        {
            List<IFeatureLayer> featLyrs = new List<IFeatureLayer>();
            if (map == null) return featLyrs;
            if (map.LayerCount == 0) return featLyrs;
            for (int i = 0; i < map.LayerCount; i++)
            {
                ILayer pLyr = map.get_Layer(i);
                GetFeaturelayers(pLyr, featLyrs, geometryType, featureType, needVisable);
            }
            return featLyrs;
        }

        /// <summary>
        /// 获取图层组下面的子图层
        /// </summary>
        /// <param name="layer"></param>
        /// <param name="featLyrs"></param>
        /// <param name="geometryType"></param>
        /// <param name="featureType"></param>
        /// <param name="needVisable"></param>
        private static void GetFeaturelayers(ILayer layer, List<IFeatureLayer> featLyrs, esriGeometryType geometryType, esriFeatureType featureType, bool needVisable)
        {
            if (needVisable && !layer.Visible) return;
            if (layer is IFeatureLayer)
            {
                IFeatureLayer featLyr = (IFeatureLayer)layer;
                if (featLyr.Valid == false) return;
                if (featLyr.FeatureClass.FeatureType == featureType)
                {
                    if (geometryType == esriGeometryType.esriGeometryAny)
                        featLyrs.Add(featLyr);
                    else
                    {
                        if (featLyr.FeatureClass.ShapeType == geometryType)
                        {
                            featLyrs.Add(featLyr);
                        }
                    }
                }
            }
            else if (layer is ICompositeLayer)
            {
                ICompositeLayer compositeLyr = (ICompositeLayer)layer;
                for (int i = 0; i < compositeLyr.Count; i++)
                {
                    ILayer lyr = compositeLyr.get_Layer(i);
                    GetFeaturelayers(lyr, featLyrs, geometryType, featureType, needVisable);
                }
            }
        }

    }
}
